`include "defines.v"

`define AXI_TOP_INTERFACE(name) io_memAXI_0_``name

module SimTop(
    input                               clock,
    input                               reset,

    input  [63:0]                       io_logCtrl_log_begin,
    input  [63:0]                       io_logCtrl_log_end,
    input  [63:0]                       io_logCtrl_log_level,
    input                               io_perfInfo_clean,
    input                               io_perfInfo_dump,

    output                              io_uart_out_valid,
    output [7:0]                        io_uart_out_ch,
    output                              io_uart_in_valid,
    input  [7:0]                        io_uart_in_ch,

    input                               `AXI_TOP_INTERFACE(aw_ready),
    output                              `AXI_TOP_INTERFACE(aw_valid),
    output [`AXI_ADDR_WIDTH-1:0]        `AXI_TOP_INTERFACE(aw_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_prot),
    output [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(aw_bits_id),
    output [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(aw_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(aw_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(aw_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(aw_bits_burst),
    output                              `AXI_TOP_INTERFACE(aw_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(aw_bits_qos),
    
    input                               `AXI_TOP_INTERFACE(w_ready),
    output                              `AXI_TOP_INTERFACE(w_valid),
    output [`AXI_DATA_WIDTH-1:0]        `AXI_TOP_INTERFACE(w_bits_data)         [3:0],
    output [`AXI_DATA_WIDTH/8-1:0]      `AXI_TOP_INTERFACE(w_bits_strb),
    output                              `AXI_TOP_INTERFACE(w_bits_last),
    
    output                              `AXI_TOP_INTERFACE(b_ready),
    input                               `AXI_TOP_INTERFACE(b_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(b_bits_resp),
    input  [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(b_bits_id),
    input  [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(b_bits_user),

    input                               `AXI_TOP_INTERFACE(ar_ready),
    output                              `AXI_TOP_INTERFACE(ar_valid),
    output [`AXI_ADDR_WIDTH-1:0]        `AXI_TOP_INTERFACE(ar_bits_addr),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_prot),
    output [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(ar_bits_id),
    output [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(ar_bits_user),
    output [7:0]                        `AXI_TOP_INTERFACE(ar_bits_len),
    output [2:0]                        `AXI_TOP_INTERFACE(ar_bits_size),
    output [1:0]                        `AXI_TOP_INTERFACE(ar_bits_burst),
    output                              `AXI_TOP_INTERFACE(ar_bits_lock),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_cache),
    output [3:0]                        `AXI_TOP_INTERFACE(ar_bits_qos),
    
    output                              `AXI_TOP_INTERFACE(r_ready),
    input                               `AXI_TOP_INTERFACE(r_valid),
    input  [1:0]                        `AXI_TOP_INTERFACE(r_bits_resp),
    input  [`AXI_DATA_WIDTH-1:0]        `AXI_TOP_INTERFACE(r_bits_data)         [3:0],
    input                               `AXI_TOP_INTERFACE(r_bits_last),
    input  [`AXI_ID_WIDTH-1:0]          `AXI_TOP_INTERFACE(r_bits_id),
    input  [`AXI_USER_WIDTH-1:0]        `AXI_TOP_INTERFACE(r_bits_user)
);
    //Definition
    //axi4
    wire [`AXI_ID_WIDTH-1:0]        aw_id;
    wire [`AXI_ADDR_WIDTH-1:0]      aw_addr;
    wire [7:0]                      aw_len;
    wire [2:0]                      aw_size;
    wire [1:0]                      aw_burst;
    wire                            aw_lock;
    wire [3:0]                      aw_cache;
    wire [2:0]                      aw_prot;
    wire [3:0]                      aw_qos;
    wire [3:0]                      aw_region;
    wire [`AXI_USER_WIDTH-1:0]      aw_user;
    wire                            aw_valid;
    wire                            aw_ready;

    wire [`AXI_DATA_WIDTH-1:0]      w_data;
    wire [`AXI_DATA_WIDTH/8-1:0]    w_strb;
    wire w_last;
    wire [`AXI_USER_WIDTH-1:0]      w_user;
    wire w_valid;
    wire w_ready;

    wire [`AXI_ID_WIDTH-1:0]        b_id;
    wire [1:0]                      b_resp;
    wire [`AXI_USER_WIDTH-1:0]      b_user;
    wire                            b_valid;
    wire                            b_ready;
    
    wire [`AXI_ID_WIDTH-1:0]        ar_id;
    wire [`AXI_ADDR_WIDTH-1:0]      ar_addr;
    wire [7:0]                      ar_len;
    wire [2:0]                      ar_size;
    wire [1:0]                      ar_burst;
    wire                            ar_lock;
    wire [3:0]                      ar_cache;
    wire [2:0]                      ar_prot;
    wire [3:0]                      ar_qos;
    wire [3:0]                      ar_region;
    wire [`AXI_USER_WIDTH-1:0]      ar_user;
    wire                            ar_valid;
    wire                            ar_ready;

    wire [`AXI_ID_WIDTH-1:0]        r_id;
    wire [`AXI_DATA_WIDTH-1:0]      r_data;
    wire [1:0]                      r_resp;
    wire                            r_last;
    wire [`AXI_USER_WIDTH-1:0]      r_user;
    wire                            r_valid;
    wire                            r_ready;

    //cpu
    wire[`RAM_ADDR_WIDTH - 1:0]     iram_addr;
    wire[`IRAM_DATA_WIDTH - 1:0]    iram_rdata;
    wire                            iram_valid;
    wire                            iram_ready;

    wire                            dram_wen;
    wire[`RAM_ADDR_WIDTH - 1:0]     dram_addr;
    wire[`RAM_DATA_WIDTH - 1:0]     dram_wdata;
    wire[`RAM_DATA_WIDTH / 8 - 1:0] dram_wmask;
    wire[`RAM_DATA_WIDTH - 1:0]     dram_rdata;
    wire[2:0]                       dram_rw_size;

    wire                            dram_valid;
    wire                            dram_ready;

    // aw
    assign `AXI_TOP_INTERFACE(aw_bits_id)           = aw_id;
    assign `AXI_TOP_INTERFACE(aw_bits_addr)         = aw_addr;
    assign `AXI_TOP_INTERFACE(aw_bits_len)          = aw_len;
    assign `AXI_TOP_INTERFACE(aw_bits_size)         = aw_size;
    assign `AXI_TOP_INTERFACE(aw_bits_burst)        = aw_burst;
    assign `AXI_TOP_INTERFACE(aw_bits_lock)         = aw_lock;
    assign `AXI_TOP_INTERFACE(aw_bits_cache)        = aw_cache;
    assign `AXI_TOP_INTERFACE(aw_bits_prot)         = aw_prot;
    assign `AXI_TOP_INTERFACE(aw_bits_qos)          = aw_qos;

    assign `AXI_TOP_INTERFACE(aw_bits_user)         = aw_user;
    assign `AXI_TOP_INTERFACE(aw_valid)             = aw_valid;
    assign aw_ready                                 = `AXI_TOP_INTERFACE(aw_ready);

    //w
    assign `AXI_TOP_INTERFACE(w_bits_data)[0]       = w_data;
    assign `AXI_TOP_INTERFACE(w_bits_strb)          = w_strb;
    assign `AXI_TOP_INTERFACE(w_bits_last)          = w_last;

    assign `AXI_TOP_INTERFACE(w_valid)              = w_valid;
    assign w_ready                                  = `AXI_TOP_INTERFACE(w_ready);
    
    //b
    assign b_id                                     = `AXI_TOP_INTERFACE(b_bits_id);    
    assign b_resp                                   = `AXI_TOP_INTERFACE(b_bits_resp);
    assign b_user                                   = `AXI_TOP_INTERFACE(b_bits_user);
    assign b_valid                                  = `AXI_TOP_INTERFACE(b_valid);
    assign `AXI_TOP_INTERFACE(b_ready)              = b_ready;

    //ar
    assign `AXI_TOP_INTERFACE(ar_bits_id)           = ar_id;
    assign `AXI_TOP_INTERFACE(ar_bits_addr)         = ar_addr;
    assign `AXI_TOP_INTERFACE(ar_bits_len)          = ar_len;
    assign `AXI_TOP_INTERFACE(ar_bits_size)         = ar_size;
    assign `AXI_TOP_INTERFACE(ar_bits_burst)        = ar_burst;
    assign `AXI_TOP_INTERFACE(ar_bits_lock)         = ar_lock;
    assign `AXI_TOP_INTERFACE(ar_bits_cache)        = ar_cache;
    assign `AXI_TOP_INTERFACE(ar_bits_prot)         = ar_prot;
    assign `AXI_TOP_INTERFACE(ar_bits_qos)          = ar_qos;

    assign `AXI_TOP_INTERFACE(ar_bits_user)         = ar_user;
    assign `AXI_TOP_INTERFACE(ar_valid)             = ar_valid;
    assign ar_ready                                 = `AXI_TOP_INTERFACE(ar_ready);
    
    //r
    assign r_id                                     = `AXI_TOP_INTERFACE(r_bits_id);
    assign r_data                                   = `AXI_TOP_INTERFACE(r_bits_data)[0];
    assign r_resp                                   = `AXI_TOP_INTERFACE(r_bits_resp);
    assign r_last                                   = `AXI_TOP_INTERFACE(r_bits_last);
    assign r_user                                   = `AXI_TOP_INTERFACE(r_bits_user);
    assign r_valid                                  = `AXI_TOP_INTERFACE(r_valid);
    assign `AXI_TOP_INTERFACE(r_ready)              = r_ready;

    arbiter_to_axi arbiter_to_axi_sim(

        .clk                    (clock),
        .rst                    (reset),

        .iram_addr              (iram_addr),
        .iram_rdata             (iram_rdata),

        .iram_valid             (iram_valid),
        .iram_ready             (iram_ready),

        .dram_wen               (dram_wen),
        .dram_addr              (dram_addr),
        .dram_wdata             (dram_wdata),
        .dram_wmask             (dram_wmask),
        .dram_rdata             (dram_rdata),
        .dram_rw_size           (dram_rw_size),

        .dram_valid             (dram_valid),
        .dram_ready             (dram_ready),
    ////////////////////////////axi interface
    // aw
        .awid                   (aw_id),
        .awaddr                 (aw_addr),
        .awlen                  (aw_len),
        .awsize                 (aw_size),
        .awburst                (aw_burst),
        .awlock                 (aw_lock),
        .awcache                (aw_cache),
        .awprot                 (aw_prot),
        .awqos                  (aw_qos),
        .awregion               (aw_region),
        .awuser                 (aw_user),
        .awvalid                (aw_valid),
        .awready                (aw_ready),
    // w
        .wdata                  (w_data),
        .wstrb                  (w_strb),
        .wlast                  (w_last),
        .wuser                  (w_user),
        .wvalid                 (w_valid),
        .wready                 (w_ready),
    // b
        .bid                    (b_id),
        .bresp                  (b_resp),
        .buser                  (b_user),
        .bvalid                 (b_valid),
        .bready                 (b_ready),
    // ar
        .arid                   (ar_id),
        .araddr                 (ar_addr),
        .arlen                  (ar_len),
        .arsize                 (ar_size),
        .arburst                (ar_burst),
        .arlock                 (ar_lock),
        .arcache                (ar_cache),
        .arprot                 (ar_prot),
        .arqos                  (ar_qos),
        .arregion               (ar_region),
        .aruser                 (ar_user),
        .arvalid                (ar_valid),
        .arready                (ar_ready),
    // r
        .rid                    (r_id),
        .rdata                  (r_data),
        .rresp                  (r_resp),
        .rlast                  (r_last),
        .ruser                  (r_user),
        .rvalid                 (r_valid),
        .rready                 (r_ready)
    );

    cpu cpu_sim(
        .clock(clock),
        .reset(reset),

        .iram_addr      (iram_addr),
        .iram_rdata     (iram_rdata),

        .iram_valid     (iram_valid),
        .iram_ready     (iram_ready),

        .dram_wen       (dram_wen),
        .dram_addr      (dram_addr),
        .dram_wdata     (dram_wdata),
        .dram_wmask     (dram_wmask),
        .dram_rdata     (dram_rdata),
        .dram_rw_size   (dram_rw_size),

        .dram_valid     (dram_valid),
        .dram_ready     (dram_ready)
    );
endmodule
